๋ณต์๋ ฅ ์๊ณ ์ฌ์ฉ์ ์นํ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถ์ ์ํด React ์ค๋ฅ ๊ฒฝ๊ณ๋ฅผ ๋ง์คํฐํ์ธ์. ๋ชจ๋ฒ ์ฌ๋ก, ๊ตฌํ ๊ธฐ์ , ๊ณ ๊ธ ์ค๋ฅ ์ฒ๋ฆฌ ์ ๋ต์ ๋ฐฐ์๋ณด์ธ์.
React ์ค๋ฅ ๊ฒฝ๊ณ: ๊ฒฌ๊ณ ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ ์ฐ์ํ ์ค๋ฅ ์ฒ๋ฆฌ ๊ธฐ๋ฒ
์ญ๋์ ์ธ ์น ๊ฐ๋ฐ ์ธ๊ณ์์ ๊ฒฌ๊ณ ํ๊ณ ์ฌ์ฉ์ ์นํ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋๋ ๊ฒ์ ๊ฐ์ฅ ์ค์ํฉ๋๋ค. ์ฌ์ฉ์ ์ธํฐํ์ด์ค ๊ตฌ์ถ์ ์ํ ์ธ๊ธฐ ์๋ ์๋ฐ์คํฌ๋ฆฝํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ React๋ ์ค๋ฅ ๊ฒฝ๊ณ(Error Boundaries)๋ผ๋ ์ค๋ฅ๋ฅผ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌํ๋ ๊ฐ๋ ฅํ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค. ์ด ์ข ํฉ ๊ฐ์ด๋์์๋ ์ค๋ฅ ๊ฒฝ๊ณ์ ๊ฐ๋ ์ ๊น์ด ํ๊ณ ๋ค์ด, ๋ณต์๋ ฅ ์๋ React ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถ์ ์ํ ๋ชฉ์ , ๊ตฌํ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ํ๊ตฌํฉ๋๋ค.
์ค๋ฅ ๊ฒฝ๊ณ์ ํ์์ฑ ์ดํดํ๊ธฐ
React ์ปดํฌ๋ํธ๋ ๋ค๋ฅธ ์ฝ๋์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ค๋ฅ์ ์ทจ์ฝํฉ๋๋ค. ์ด๋ฌํ ์ค๋ฅ๋ ๋ค์๊ณผ ๊ฐ์ ๋ค์ํ ์์ธ์์ ๋ฐ์ํ ์ ์์ต๋๋ค:
- ์์์น ๋ชปํ ๋ฐ์ดํฐ: ์ปดํฌ๋ํธ๊ฐ ์์์น ๋ชปํ ํ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ๋ ๋๋ง ๋ฌธ์ ๋ฅผ ์ผ์ผํฌ ์ ์์ต๋๋ค.
- ๋ก์ง ์ค๋ฅ: ์ปดํฌ๋ํธ ๋ก์ง์ ๋ฒ๊ทธ๊ฐ ์๊ธฐ์น ์์ ๋์๊ณผ ์ค๋ฅ๋ฅผ ์ ๋ฐํ ์ ์์ต๋๋ค.
- ์ธ๋ถ ์ข ์์ฑ: ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ API์ ๋ฌธ์ ๊ฐ ์ปดํฌ๋ํธ๋ก ์ค๋ฅ๋ฅผ ์ ํํ ์ ์์ต๋๋ค.
์ ์ ํ ์ค๋ฅ ์ฒ๋ฆฌ ์์ด๋ React ์ปดํฌ๋ํธ์ ์ค๋ฅ๊ฐ ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค๋จ์์ผ ์ข์ง ์์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ด๋ํ ์ ์์ต๋๋ค. ์ค๋ฅ ๊ฒฝ๊ณ๋ ์ด๋ฌํ ์ค๋ฅ๋ฅผ ํฌ์ฐฉํ๊ณ ์ปดํฌ๋ํธ ํธ๋ฆฌ ์๋ก ์ ํ๋๋ ๊ฒ์ ๋ฐฉ์งํ์ฌ, ๊ฐ๋ณ ์ปดํฌ๋ํธ๊ฐ ์คํจํ๋๋ผ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๊ณ์ ์๋ํ๋๋ก ๋ณด์ฅํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
React ์ค๋ฅ ๊ฒฝ๊ณ๋ ๋ฌด์์ธ๊ฐ?
์ค๋ฅ ๊ฒฝ๊ณ๋ ์์ ์ปดํฌ๋ํธ ํธ๋ฆฌ ์ด๋์์๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ค๋ฅ๋ฅผ ํฌ์ฐฉํ๊ณ , ํด๋น ์ค๋ฅ๋ฅผ ๊ธฐ๋กํ๋ฉฐ, ์ถฉ๋ํ ์ปดํฌ๋ํธ ํธ๋ฆฌ ๋์ ๋์ฒด UI๋ฅผ ํ์ํ๋ React ์ปดํฌ๋ํธ์ ๋๋ค. ์ด๋ ์์ ๋ง ์ญํ ์ ํ์ฌ ์ค๋ฅ๊ฐ ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค๋จ์ํค๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค.
์ค๋ฅ ๊ฒฝ๊ณ์ ์ฃผ์ ํน์ง:
- ํด๋์ค ์ปดํฌ๋ํธ ์ ์ฉ: ์ค๋ฅ ๊ฒฝ๊ณ๋ ๋ฐ๋์ ํด๋์ค ์ปดํฌ๋ํธ๋ก ๊ตฌํํด์ผ ํฉ๋๋ค. ํจ์ํ ์ปดํฌ๋ํธ์ ํ ์ ์ค๋ฅ ๊ฒฝ๊ณ๋ฅผ ๋ง๋๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ์๋ช
์ฃผ๊ธฐ ๋ฉ์๋: ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด
static getDerivedStateFromError()์componentDidCatch()๋ผ๋ ํน์ ์๋ช ์ฃผ๊ธฐ ๋ฉ์๋๋ฅผ ์ฌ์ฉํฉ๋๋ค. - ์ง์ญ์ ์ค๋ฅ ์ฒ๋ฆฌ: ์ค๋ฅ ๊ฒฝ๊ณ๋ ์์ ๋ด๋ถ๊ฐ ์๋ ์์ ์ปดํฌ๋ํธ์ ์ค๋ฅ๋ง ํฌ์ฐฉํฉ๋๋ค.
์ค๋ฅ ๊ฒฝ๊ณ ๊ตฌํํ๊ธฐ
๊ธฐ๋ณธ์ ์ธ ์ค๋ฅ ๊ฒฝ๊ณ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋๋ ๊ณผ์ ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค:
1. ์ค๋ฅ ๊ฒฝ๊ณ ์ปดํฌ๋ํธ ๋ง๋ค๊ธฐ
๋จผ์ , ErrorBoundary์ ๊ฐ์ด ์๋ก์ด ํด๋์ค ์ปดํฌ๋ํธ๋ฅผ ์์ฑํฉ๋๋ค:
import React from 'react';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = {
hasError: false
};
}
static getDerivedStateFromError(error) {
// ๋ค์ ๋ ๋๋ง์์ ๋์ฒด UI๋ฅผ ํ์ํ๋๋ก ์ํ๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค.
return {
hasError: true
};
}
componentDidCatch(error, errorInfo) {
// ์ค๋ฅ ๋ณด๊ณ ์๋น์ค์ ์ค๋ฅ๋ฅผ ๊ธฐ๋กํ ์๋ ์์ต๋๋ค.
console.error("Caught error: ", error, errorInfo);
// ์์: logErrorToMyService(error, errorInfo);
}
render() {
if (this.state.hasError) {
// ์ฌ์ฉ์ ์ ์ ๋์ฒด UI๋ฅผ ๋ ๋๋งํ ์ ์์ต๋๋ค.
return (
<div>
<h2>๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.</h2>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.error && this.state.error.toString()}
<br />
{this.state.errorInfo.componentStack}
</details>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
์ค๋ช :
- Constructor: ์ปดํฌ๋ํธ์ ์ํ๋ฅผ
hasError: false๋ก ์ด๊ธฐํํฉ๋๋ค. static getDerivedStateFromError(error): ์ด ์๋ช ์ฃผ๊ธฐ ๋ฉ์๋๋ ํ์ ์ปดํฌ๋ํธ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ ํ์ ํธ์ถ๋ฉ๋๋ค. ์ค๋ฅ๋ฅผ ์ธ์๋ก ๋ฐ์ ์ปดํฌ๋ํธ์ ์ํ๋ฅผ ์ ๋ฐ์ดํธํ ์ ์๊ฒ ํด์ค๋๋ค. ์ฌ๊ธฐ์๋hasError๋ฅผtrue๋ก ์ค์ ํ์ฌ ๋์ฒด UI๋ฅผ ํ์ํ๋๋ก ํฉ๋๋ค. ์ด ๋ฉ์๋๋static๋ฉ์๋์ด๋ฏ๋ก ํจ์ ๋ด์์this๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.componentDidCatch(error, errorInfo): ์ด ์๋ช ์ฃผ๊ธฐ ๋ฉ์๋๋ ํ์ ์ปดํฌ๋ํธ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ ํ์ ํธ์ถ๋ฉ๋๋ค. ๋ ๊ฐ์ง ์ธ์๋ฅผ ๋ฐ์ต๋๋ค:error: ๋ฐ์ํ ์ค๋ฅ์ ๋๋ค.errorInfo: ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ปดํฌ๋ํธ ์คํ์ ๋ํ ์ ๋ณด๊ฐ ํฌํจ๋ ๊ฐ์ฒด์ ๋๋ค. ๋๋ฒ๊น ์ ๋งค์ฐ ์ ์ฉํฉ๋๋ค.
์ด ๋ฉ์๋ ๋ด์์ Sentry, Rollbar ๋๋ ์ฌ์ฉ์ ์ ์ ๋ก๊น ์๋ฃจ์ ๊ณผ ๊ฐ์ ์๋น์ค์ ์ค๋ฅ๋ฅผ ๊ธฐ๋กํ ์ ์์ต๋๋ค. ์ด ํจ์ ๋ด์์ ์ง์ ์ค๋ฅ๋ฅผ ๋ค์ ๋ ๋๋งํ๊ฑฐ๋ ์์ ํ๋ ค๊ณ ํ์ง ๋ง์ธ์. ์ฃผ์ ๋ชฉ์ ์ ๋ฌธ์ ๋ฅผ ๊ธฐ๋กํ๋ ๊ฒ์ ๋๋ค.
render(): render ๋ฉ์๋๋hasError์ํ๋ฅผ ํ์ธํฉ๋๋ค.true์ด๋ฉด ๋์ฒด UI(์ด ๊ฒฝ์ฐ ๊ฐ๋จํ ์ค๋ฅ ๋ฉ์์ง)๋ฅผ ๋ ๋๋งํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ปดํฌ๋ํธ์ ์์๋ค์ ๋ ๋๋งํฉ๋๋ค.
2. ์ค๋ฅ ๊ฒฝ๊ณ ์ฌ์ฉํ๊ธฐ
์ค๋ฅ ๊ฒฝ๊ณ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ค๋ฅ๋ฅผ ๋ฐ์์ํฌ ์ ์๋ ๋ชจ๋ ์ปดํฌ๋ํธ๋ฅผ ErrorBoundary ์ปดํฌ๋ํธ๋ก ๊ฐ์ธ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค:
import ErrorBoundary from './ErrorBoundary';
function MyComponent() {
// ์ด ์ปดํฌ๋ํธ๋ ์ค๋ฅ๋ฅผ ๋ฐ์์ํฌ ์ ์์ต๋๋ค.
return (
<ErrorBoundary>
<PotentiallyBreakingComponent />
</ErrorBoundary>
);
}
export default MyComponent;
๋ง์ฝ PotentiallyBreakingComponent๊ฐ ์ค๋ฅ๋ฅผ ๋ฐ์์ํค๋ฉด, ErrorBoundary๊ฐ ์ด๋ฅผ ํฌ์ฐฉํ๊ณ ์ค๋ฅ๋ฅผ ๊ธฐ๋กํ ํ ๋์ฒด UI๋ฅผ ๋ ๋๋งํฉ๋๋ค.
3. ์ ์ญ ์ปจํ ์คํธ๋ฅผ ์ฌ์ฉํ ์์
์๊ฒฉ ์๋ฒ์์ ๊ฐ์ ธ์จ ์ํ ์ ๋ณด๋ฅผ ํ์ํ๋ ์ ์์๊ฑฐ๋ ์ ํ๋ฆฌ์ผ์ด์
์ ์๊ฐํด๋ณด์ธ์. ProductDisplay๋ผ๋ ์ปดํฌ๋ํธ๊ฐ ์ํ ์์ธ ์ ๋ณด๋ฅผ ๋ ๋๋งํ๋ ์ญํ ์ ํฉ๋๋ค. ํ์ง๋ง ์๋ฒ๊ฐ ๋๋๋ก ์์์น ๋ชปํ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ์ฌ ๋ ๋๋ง ์ค๋ฅ๋ฅผ ์ผ์ผํฌ ์ ์์ต๋๋ค.
// ProductDisplay.js
import React from 'react';
function ProductDisplay({ product }) {
// product.price๊ฐ ์ซ์๊ฐ ์๋ ๊ฒฝ์ฐ ๋ฐ์ํ ์ ์๋ ์ค๋ฅ๋ฅผ ์๋ฎฌ๋ ์ด์
ํฉ๋๋ค.
if (typeof product.price !== 'number') {
throw new Error('Invalid product price');
}
return (
<div>
<h2>{product.name}</h2>
<p>Price: {product.price}</p>
<img src={product.imageUrl} alt={product.name} />
</div>
);
}
export default ProductDisplay;
์ด๋ฌํ ์ค๋ฅ๋ก๋ถํฐ ๋ณดํธํ๊ธฐ ์ํด ProductDisplay ์ปดํฌ๋ํธ๋ฅผ ErrorBoundary๋ก ๊ฐ์ธ์ค๋๋ค:
// App.js
import React from 'react';
import ErrorBoundary from './ErrorBoundary';
import ProductDisplay from './ProductDisplay';
function App() {
const product = {
name: 'Example Product',
price: 'Not a Number', // ์๋์ ์ผ๋ก ์๋ชป๋ ๋ฐ์ดํฐ
imageUrl: 'https://example.com/image.jpg'
};
return (
<div>
<ErrorBoundary>
<ProductDisplay product={product} />
</ErrorBoundary>
</div>
);
}
export default App;
์ด ์๋๋ฆฌ์ค์์๋ product.price๊ฐ ์๋์ ์ผ๋ก ์ซ์๊ฐ ์๋ ๋ฌธ์์ด๋ก ์ค์ ๋์๊ธฐ ๋๋ฌธ์ ProductDisplay ์ปดํฌ๋ํธ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค. ErrorBoundary๋ ์ด ์ค๋ฅ๋ฅผ ํฌ์ฐฉํ์ฌ ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์
์ ์ค๋จ์ ๋ง๊ณ , ๊นจ์ง ProductDisplay ์ปดํฌ๋ํธ ๋์ ๋์ฒด UI๋ฅผ ํ์ํฉ๋๋ค.
4. ๊ตญ์ ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์์์ ์ค๋ฅ ๊ฒฝ๊ณ
๊ธ๋ก๋ฒ ์ฌ์ฉ์๋ฅผ ์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ๋, ๋ ๋์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ๊ธฐ ์ํด ์ค๋ฅ ๋ฉ์์ง๋ ํ์งํ๋์ด์ผ ํฉ๋๋ค. ์ค๋ฅ ๊ฒฝ๊ณ๋ ๊ตญ์ ํ(i18n) ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํจ๊ป ์ฌ์ฉํ์ฌ ๋ฒ์ญ๋ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ํ์ํ ์ ์์ต๋๋ค.
// ErrorBoundary.js (i18n ์ง์ ํฌํจ)
import React from 'react';
import { useTranslation } from 'react-i18next'; // react-i18next๋ฅผ ์ฌ์ฉํ๋ค๊ณ ๊ฐ์
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = {
hasError: false,
error: null,
errorInfo: null,
};
}
static getDerivedStateFromError(error) {
return {
hasError: true,
error: error,
};
}
componentDidCatch(error, errorInfo) {
console.error("Caught error: ", error, errorInfo);
this.setState({errorInfo: errorInfo});
}
render() {
if (this.state.hasError) {
return (
<FallbackUI error={this.state.error} errorInfo={this.state.errorInfo}/>
);
}
return this.props.children;
}
}
const FallbackUI = ({error, errorInfo}) => {
const { t } = useTranslation();
return (
<div>
<h2>{t('error.title')}</h2>
<p>{t('error.message')}</p>
<details style={{ whiteSpace: 'pre-wrap' }}>
{error && error.toString()}<br />
{errorInfo?.componentStack}
</details>
</div>
);
}
export default ErrorBoundary;
์ด ์์ ์์๋ react-i18next๋ฅผ ์ฌ์ฉํ์ฌ ๋์ฒด UI์ ์ค๋ฅ ์ ๋ชฉ๊ณผ ๋ฉ์์ง๋ฅผ ๋ฒ์ญํฉ๋๋ค. t('error.title') ๋ฐ t('error.message') ํจ์๋ ์ฌ์ฉ์๊ฐ ์ ํํ ์ธ์ด์ ๋ฐ๋ผ ์ ์ ํ ๋ฒ์ญ์ ๊ฐ์ ธ์ต๋๋ค.
5. ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง(SSR) ๊ณ ๋ ค์ฌํญ
์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ค๋ฅ ๊ฒฝ๊ณ๋ฅผ ์ฌ์ฉํ ๋, ์๋ฒ๊ฐ ์ถฉ๋ํ๋ ๊ฒ์ ๋ฐฉ์งํ๊ธฐ ์ํด ์ค๋ฅ๋ฅผ ์ ์ ํ๊ฒ ์ฒ๋ฆฌํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. React ๋ฌธ์์์๋ ์๋ฒ์์์ ๋ ๋๋ง ์ค๋ฅ ๋ณต๊ตฌ๋ฅผ ์ํด ์ค๋ฅ ๊ฒฝ๊ณ๋ฅผ ์ฌ์ฉํ์ง ๋ง ๊ฒ์ ๊ถ์ฅํฉ๋๋ค. ๋์ , ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ๊ธฐ ์ ์ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๊ฑฐ๋ ์๋ฒ์์ ์ ์ ์ค๋ฅ ํ์ด์ง๋ฅผ ๋ ๋๋งํ์ธ์.
์ค๋ฅ ๊ฒฝ๊ณ ์ฌ์ฉ์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก
- ์ธ๋ถํ๋ ์ปดํฌ๋ํธ ๊ฐ์ธ๊ธฐ: ๊ฐ๋ณ ์ปดํฌ๋ํธ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ ๋ถ๋ถ์ ์ค๋ฅ ๊ฒฝ๊ณ๋ก ๊ฐ์ธ์ธ์. ์ด๋ ๋จ์ผ ์ค๋ฅ๊ฐ ์ ์ฒด UI๋ฅผ ์ค๋จ์ํค๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค. ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ๋ณด๋ค๋ ํน์ ๊ธฐ๋ฅ์ด๋ ๋ชจ๋์ ๊ฐ์ธ๋ ๊ฒ์ ๊ณ ๋ คํ์ธ์.
- ์ค๋ฅ ๊ธฐ๋กํ๊ธฐ:
componentDidCatch()๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ชจ๋ํฐ๋ง ์๋น์ค์ ์ค๋ฅ๋ฅผ ๊ธฐ๋กํ์ธ์. ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฌธ์ ๋ฅผ ์ถ์ ํ๊ณ ์์ ํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค. Sentry, Rollbar, Bugsnag์ ๊ฐ์ ์๋น์ค๋ ์ค๋ฅ ์ถ์ ๋ฐ ๋ณด๊ณ ์ ๋๋ฆฌ ์ฌ์ฉ๋๋ ์ ํ์ง์ ๋๋ค. - ์ ๋ณด์ฑ ์๋ ๋์ฒด UI ์ ๊ณตํ๊ธฐ: ๋์ฒด UI์ ์ฌ์ฉ์ ์นํ์ ์ธ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ํ์ํ์ธ์. ๊ธฐ์ ์ ์ธ ์ ๋ฌธ ์ฉ์ด๋ฅผ ํผํ๊ณ , ํ์ด์ง ์๋ก๊ณ ์นจ์ด๋ ๊ณ ๊ฐ ์ง์ ๋ฌธ์์ ๊ฐ์ด ์ฌ์ฉ์๊ฐ ์ทจํ ์ ์๋ ๋ค์ ๋จ๊ณ๋ฅผ ์๋ดํ์ธ์. ๊ฐ๋ฅํ๋ค๋ฉด ์ฌ์ฉ์๊ฐ ์ทจํ ์ ์๋ ๋์์ ์ธ ํ๋์ ์ ์ํ์ธ์.
- ๊ณผ๋ํ๊ฒ ์ฌ์ฉํ์ง ์๊ธฐ: ๋ชจ๋ ๋จ์ผ ์ปดํฌ๋ํธ๋ฅผ ์ค๋ฅ ๊ฒฝ๊ณ๋ก ๊ฐ์ธ๋ ๊ฒ์ ํผํ์ธ์. ์ธ๋ถ API์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ฑฐ๋ ๋ณต์กํ ์ฌ์ฉ์ ์ํธ์์ฉ์ ์ฒ๋ฆฌํ๋ ์ปดํฌ๋ํธ์ ๊ฐ์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ ๊ฐ๋ฅ์ฑ์ด ๋ ๋์ ์์ญ์ ์ง์คํ์ธ์.
- ์ค๋ฅ ๊ฒฝ๊ณ ํ ์คํธํ๊ธฐ: ์ค๋ฅ ๊ฒฝ๊ณ๋ก ๊ฐ์ผ ์ปดํฌ๋ํธ์์ ์๋์ ์ผ๋ก ์ค๋ฅ๋ฅผ ๋ฐ์์์ผ ์ค๋ฅ ๊ฒฝ๊ณ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํ์ธ์. ๋จ์ ํ ์คํธ๋ ํตํฉ ํ ์คํธ๋ฅผ ์์ฑํ์ฌ ๋์ฒด UI๊ฐ ์์๋๋ก ํ์๋๊ณ ์ค๋ฅ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๊ธฐ๋ก๋๋์ง ํ์ธํ์ธ์.
- ์ค๋ฅ ๊ฒฝ๊ณ๋ ๋ค์ ์ฉ๋๊ฐ ์๋๋๋ค:
- ์ด๋ฒคํธ ํธ๋ค๋ฌ
- ๋น๋๊ธฐ ์ฝ๋ (์:
setTimeout๋๋requestAnimationFrame์ฝ๋ฐฑ) - ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง
- ์ค๋ฅ ๊ฒฝ๊ณ ์์ฒด(์์์ด ์๋)์์ ๋ฐ์ํ ์ค๋ฅ
๊ณ ๊ธ ์ค๋ฅ ์ฒ๋ฆฌ ์ ๋ต
1. ์ฌ์๋ ๋ฉ์ปค๋์ฆ
๊ฒฝ์ฐ์ ๋ฐ๋ผ, ์ค๋ฅ๋ฅผ ์ ๋ฐํ ์์ ์ ์ฌ์๋ํ์ฌ ์ค๋ฅ๋ก๋ถํฐ ๋ณต๊ตฌํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๋คํธ์ํฌ ์์ฒญ์ด ์คํจํ๋ฉด ์งง์ ์ง์ฐ ํ ์ฌ์๋ํ ์ ์์ต๋๋ค. ์ค๋ฅ ๊ฒฝ๊ณ๋ ์ฌ์๋ ๋ฉ์ปค๋์ฆ๊ณผ ๊ฒฐํฉํ์ฌ ๋ ๋ณต์๋ ฅ ์๋ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ ์ ์์ต๋๋ค.
// ErrorBoundaryWithRetry.js
import React from 'react';
class ErrorBoundaryWithRetry extends React.Component {
constructor(props) {
super(props);
this.state = {
hasError: false,
retryCount: 0,
};
}
static getDerivedStateFromError(error) {
return {
hasError: true,
};
}
componentDidCatch(error, errorInfo) {
console.error("Caught error: ", error, errorInfo);
}
handleRetry = () => {
this.setState(prevState => ({
hasError: false,
retryCount: prevState.retryCount + 1,
}), () => {
// ์ด๋ ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ ๋ก ๋ค์ ๋ ๋๋งํฉ๋๋ค. ์ ์ด๋๋ props๋ฅผ ์ฌ์ฉํ๋ ๋ ๋์ ํจํด์ ๊ณ ๋ คํ์ธ์.
this.forceUpdate(); // ๊ฒฝ๊ณ : ์ฃผ์ํด์ ์ฌ์ฉํ์ธ์
if (this.props.onRetry) {
this.props.onRetry();
}
});
};
render() {
if (this.state.hasError) {
return (
<div>
<h2>๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.</h2>
<button onClick={this.handleRetry}>์ฌ์๋</button>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundaryWithRetry;
ErrorBoundaryWithRetry ์ปดํฌ๋ํธ๋ ํด๋ฆญ ์ hasError ์ํ๋ฅผ ์ฌ์ค์ ํ๊ณ ์์ ์ปดํฌ๋ํธ๋ฅผ ๋ค์ ๋ ๋๋งํ๋ ์ฌ์๋ ๋ฒํผ์ ํฌํจํฉ๋๋ค. ์ฌ์๋ ํ์๋ฅผ ์ ํํ๊ธฐ ์ํด retryCount๋ฅผ ์ถ๊ฐํ ์๋ ์์ต๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ์ผ์์ ์ธ ๋คํธ์ํฌ ์ค๋จ๊ณผ ๊ฐ์ ์ผ์์ ์ธ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐ ํนํ ์ ์ฉํ ์ ์์ต๋๋ค. `onRetry` prop์ด ์ ์ ํ๊ฒ ์ฒ๋ฆฌ๋์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ์ ์ ์๋ ๋ก์ง์ ๋ค์ ๊ฐ์ ธ์ค๊ฑฐ๋ ์ฌ์คํํ๋๋ก ํด์ผ ํฉ๋๋ค.
2. ๊ธฐ๋ฅ ํ๋๊ทธ
๊ธฐ๋ฅ ํ๋๊ทธ๋ฅผ ์ฌ์ฉํ๋ฉด ์ ์ฝ๋๋ฅผ ๋ฐฐํฌํ์ง ์๊ณ ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ธฐ๋ฅ์ ๋์ ์ผ๋ก ํ์ฑํํ๊ฑฐ๋ ๋นํ์ฑํํ ์ ์์ต๋๋ค. ์ค๋ฅ ๊ฒฝ๊ณ๋ ๊ธฐ๋ฅ ํ๋๊ทธ์ ํจ๊ป ์ฌ์ฉํ์ฌ ์ค๋ฅ ๋ฐ์ ์ ๊ธฐ๋ฅ์ ์ ์ง์ ์ผ๋ก ์ ํ์ํฌ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ํน์ ๊ธฐ๋ฅ์ด ์ค๋ฅ๋ฅผ ์ผ์ผํค๋ ๊ฒฝ์ฐ ๊ธฐ๋ฅ ํ๋๊ทธ๋ฅผ ์ฌ์ฉํ์ฌ ํด๋น ๊ธฐ๋ฅ์ ๋นํ์ฑํํ๊ณ ์ฌ์ฉ์์๊ฒ ํด๋น ๊ธฐ๋ฅ์ด ์ผ์์ ์ผ๋ก ์ฌ์ฉํ ์ ์์์ ์๋ฆฌ๋ ๋ฉ์์ง๋ฅผ ํ์ํ ์ ์์ต๋๋ค.
3. ์ํท ๋ธ๋ ์ด์ปค ํจํด
์ํท ๋ธ๋ ์ด์ปค ํจํด์ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์คํจํ ๊ฐ๋ฅ์ฑ์ด ๋์ ์์ ์ ๋ฐ๋ณต์ ์ผ๋ก ์คํํ๋ ๊ฒ์ ๋ฐฉ์งํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ ์ํํธ์จ์ด ๋์์ธ ํจํด์ ๋๋ค. ์ด๋ ์์ ์ ์ฑ๊ณต ๋ฐ ์คํจ์จ์ ๋ชจ๋ํฐ๋งํ๊ณ , ์คํจ์จ์ด ํน์ ์๊ณ๊ฐ์ ์ด๊ณผํ๋ฉด 'ํ๋ก๋ฅผ ์ด์ด' ์ผ์ ๊ธฐ๊ฐ ๋์ ํด๋น ์์ ์ ์ถ๊ฐ ์คํ์ ๋ฐฉ์งํ๋ ๋ฐฉ์์ผ๋ก ์๋ํฉ๋๋ค. ์ด๋ ์ฐ์์ ์ธ ์คํจ๋ฅผ ๋ฐฉ์งํ๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ๋ฐ์ ์ธ ์์ ์ฑ์ ํฅ์์ํค๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
์ค๋ฅ ๊ฒฝ๊ณ๋ React ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ํท ๋ธ๋ ์ด์ปค ํจํด์ ๊ตฌํํ๋ ๋ฐ ์ฌ์ฉ๋ ์ ์์ต๋๋ค. ์ค๋ฅ ๊ฒฝ๊ณ๊ฐ ์ค๋ฅ๋ฅผ ํฌ์ฐฉํ๋ฉด ์คํจ ์นด์ดํฐ๋ฅผ ์ฆ๊ฐ์ํฌ ์ ์์ต๋๋ค. ์คํจ ์นด์ดํฐ๊ฐ ์๊ณ๊ฐ์ ์ด๊ณผํ๋ฉด ์ค๋ฅ ๊ฒฝ๊ณ๋ ์ฌ์ฉ์์๊ฒ ํด๋น ๊ธฐ๋ฅ์ ์ผ์์ ์ผ๋ก ์ฌ์ฉํ ์ ์์์ ์๋ฆฌ๋ ๋ฉ์์ง๋ฅผ ํ์ํ๊ณ ํด๋น ์์ ์ ์ถ๊ฐ ์คํ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค. ์ผ์ ์๊ฐ์ด ์ง๋๋ฉด ์ค๋ฅ ๊ฒฝ๊ณ๋ 'ํ๋ก๋ฅผ ๋ซ๊ณ ' ์์ ์คํ์ ๋ค์ ํ์ฉํ ์ ์์ต๋๋ค.
๊ฒฐ๋ก
React ์ค๋ฅ ๊ฒฝ๊ณ๋ ๊ฒฌ๊ณ ํ๊ณ ์ฌ์ฉ์ ์นํ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ ํ์์ ์ธ ๋๊ตฌ์ ๋๋ค. ์ค๋ฅ ๊ฒฝ๊ณ๋ฅผ ๊ตฌํํจ์ผ๋ก์จ ์ค๋ฅ๊ฐ ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค๋จ์ํค๋ ๊ฒ์ ๋ฐฉ์งํ๊ณ , ์ฌ์ฉ์์๊ฒ ์ฐ์ํ ๋์ฒด UI๋ฅผ ์ ๊ณตํ๋ฉฐ, ๋๋ฒ๊น ๋ฐ ๋ถ์์ ์ํด ๋ชจ๋ํฐ๋ง ์๋น์ค์ ์ค๋ฅ๋ฅผ ๊ธฐ๋กํ ์ ์์ต๋๋ค. ์ด ๊ฐ์ด๋์์ ์ค๋ช ํ ๋ชจ๋ฒ ์ฌ๋ก์ ๊ณ ๊ธ ์ ๋ต์ ๋ฐ๋ฅด๋ฉด, ์์์น ๋ชปํ ์ค๋ฅ์ ์ง๋ฉดํ๋๋ผ๋ ๋ณต์๋ ฅ ์๊ณ ์ ๋ขฐํ ์ ์์ผ๋ฉฐ ๊ธ์ ์ ์ธ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ๋ React ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ์ ์์ต๋๋ค. ๊ธ๋ก๋ฒ ์ฌ์ฉ์๋ฅผ ์ํด ํ์งํ๋ ์ ์ฉํ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ์ ๊ณตํ๋ ๋ฐ ์ง์คํ๋ ๊ฒ์ ๊ธฐ์ตํ์ธ์.